package org.space.galaxyCabinet.service.impl;

import com.influxdb.client.InfluxDBClient;
import com.influxdb.client.QueryApi;
import com.influxdb.client.WriteApi;
import com.influxdb.client.domain.WritePrecision;
import com.influxdb.query.FluxRecord;
import com.influxdb.query.FluxTable;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.space.galaxyCabinet.domain.DeviceLog;
import org.space.galaxyCabinet.domain.DeviceStatus;
import org.space.galaxyCabinet.service.InfluxDBService;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Slf4j
@Service
public class InfluxDBServiceImpl implements InfluxDBService {

    @Resource
    private InfluxDBClient deviceLogClient;
    @Resource
    private InfluxDBClient deviceStatusClient;

    @Override
    public boolean uploadedDeviceStatus(DeviceStatus deviceStatus) {
        log.info("deviceStatus: {}", deviceStatus);
        try (WriteApi writeApi = deviceStatusClient.getWriteApi()) {
            writeApi.writeMeasurement(WritePrecision.NS, deviceStatus);
            writeApi.flush();
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }

    @Override
    public boolean uploadedDeviceLog(DeviceLog deviceLog) {
        try (WriteApi writeApi = deviceLogClient.getWriteApi()) {
            writeApi.writeMeasurement(WritePrecision.NS, deviceLog);
            writeApi.flush();
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }

    /**
     * 根据条件查询 DeviceStatus 数据
     *
     * @param deviceNo 设备编号
     * @param startDate    开始时间 (毫秒)
     * @param endDate      结束时间 (毫秒)
     * @return 查询到的 DeviceStatus 数据列表
     */
    public List<DeviceStatus> queryDeviceStatusByConditions(String deviceNo, String startDate, String endDate) {
        List<DeviceStatus> deviceStatusList = new ArrayList<>();

        // 定义日期格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 将传入的日期字符串解析为 LocalDateTime
        LocalDateTime startDateTime = LocalDateTime.parse(startDate, formatter);
        LocalDateTime endDateTime = LocalDateTime.parse(endDate, formatter);

        // 将 LocalDateTime 转换为毫秒时间戳
        long start = startDateTime.toInstant(ZoneOffset.UTC).toEpochMilli();
        long end = endDateTime.toInstant(ZoneOffset.UTC).toEpochMilli();

        QueryApi queryApi = deviceStatusClient.getQueryApi();
        String fluxQuery = "from(bucket: \"cabinet\")" +
            "  |> range(start: " + start + "ms, stop: " + end + "ms)" +
            "  |> filter(fn: (r) => r[\"_measurement\"] == \"cabinet\")" +
            "  |> filter(fn: (r) => r[\"_field\"] == \"humidity\" or r[\"_field\"] == \"status\" or r[\"_field\"] == \"temperature\")" +
            "  |> filter(fn: (r) => r[\"deviceNo\"] == \"" + deviceNo + "\")" +
            "  |> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false)" +
            "  |> yield(name: \"mean\")";

        List<FluxTable> tables = queryApi.query(fluxQuery);

        for (FluxTable table : tables) {
            for (FluxRecord record : table.getRecords()) {
                DeviceStatus deviceStatus = new DeviceStatus();
                deviceStatus.setDeviceNo(record.getValueByKey("deviceNo").toString());
                deviceStatus.setHumidity(((Number) record.getValueByKey("humidity")).floatValue());
                deviceStatus.setTemperature(((Number) record.getValueByKey("temperature")).floatValue());
                deviceStatusList.add(deviceStatus);
            }
        }
        return deviceStatusList;
    }
    public List<DeviceStatus> queryDeviceStatusByConditions(String deviceNo) {
        List<DeviceStatus> deviceStatusList = new ArrayList<>();

        QueryApi queryApi = deviceStatusClient.getQueryApi();
        String fluxQuery = "from(bucket: \"cabinet\")" +
            "  |> range(start: -24h)" +
            "  |> filter(fn: (r) => r[\"_measurement\"] == \"cabinet\")" +
            "  |> filter(fn: (r) => r[\"_field\"] == \"humidity\" or r[\"_field\"] == \"status\" or r[\"_field\"] == \"temperature\")" +
            "  |> filter(fn: (r) => r[\"deviceNo\"] == \"" + deviceNo + "\")";

        List<FluxTable> tables = queryApi.query(fluxQuery);

        List<Float> humidityList = new ArrayList<>();
        List<Float> temperatureList = new ArrayList<>();
        List<Integer> statusList = new ArrayList<>();
        for (FluxTable table : tables) {
            for (FluxRecord record : table.getRecords()) {

                String value = String.valueOf(record.getValue());
                String key = String.valueOf(record.getField());

                if (key.equals("humidity")) {
                    humidityList.add(Float.parseFloat(value));
                } else if (key.equals("temperature")) {
                    temperatureList.add(Float.parseFloat(value));
                } else if (key.equals("status")) {
                    statusList.add(Integer.parseInt(value));
                }
            }
        }
        for (int index=0; index < humidityList.size(); index++) {
            DeviceStatus deviceStatus = new DeviceStatus();
            deviceStatus.setDeviceNo(deviceNo);
            deviceStatus.setHumidity(humidityList.get(index));
            deviceStatus.setTemperature(temperatureList.get(index));
            deviceStatusList.add(deviceStatus);
        }
        return deviceStatusList;
    }

    @Override
    public DeviceStatus queryLastDeviceStatusByConditions(String deviceNo) {
        List<DeviceStatus> deviceStatusList = new ArrayList<>();

        QueryApi queryApi = deviceStatusClient.getQueryApi();
        String fluxQuery = "from(bucket: \"cabinet\")" +
            "  |> range(start: -1h)" +
            "  |> filter(fn: (r) => r[\"_measurement\"] == \"cabinet\")" +
            "  |> filter(fn: (r) => r[\"_field\"] == \"humidity\" or r[\"_field\"] == \"status\" or r[\"_field\"] == \"temperature\")" +
            "  |> filter(fn: (r) => r[\"deviceNo\"] == \"" + deviceNo + "\")";

        List<FluxTable> tables = queryApi.query(fluxQuery);

        List<Float> humidityList = new ArrayList<>();
        List<Float> temperatureList = new ArrayList<>();
        List<Integer> statusList = new ArrayList<>();
        for (FluxTable table : tables) {
            for (FluxRecord record : table.getRecords()) {

                String value = String.valueOf(record.getValue());
                String key = String.valueOf(record.getField());

                if (key.equals("humidity")) {
                    humidityList.add(Float.parseFloat(value));
                } else if (key.equals("temperature")) {
                    temperatureList.add(Float.parseFloat(value));
                } else if (key.equals("status")) {
                    statusList.add(Integer.parseInt(value));
                }
            }
        }
        for (int index=0; index < humidityList.size(); index++) {
            DeviceStatus deviceStatus = new DeviceStatus();
            deviceStatus.setDeviceNo(deviceNo);
            deviceStatus.setHumidity(humidityList.get(index));
            deviceStatus.setTemperature(temperatureList.get(index));
            deviceStatusList.add(deviceStatus);
        }
        if (!deviceStatusList.isEmpty()) {
            return deviceStatusList.get(0);
        }
        return null;
    }

    /**
     * 根据条件查询 DeviceLog 数据
     *
     * @param deviceNo 设备编号
     * @param start    开始时间 (毫秒)
     * @param end      结束时间 (毫秒)
     * @return 查询到的 DeviceLog 数据列表
     */
    @Override
    public List<DeviceLog> queryDeviceLogByConditions(String deviceNo, LocalDateTime start, LocalDateTime end) {
        List<DeviceLog> deviceLogList = new ArrayList<>();

        QueryApi queryApi = deviceLogClient.getQueryApi();
        String fluxQuery = "from(bucket: \"deviceLog\")" +
            "  |> range(start: -24h)" +
            "  |> filter(fn: (r) => r[\"_measurement\"] == \"deviceLog\")" +
            "  |> filter(fn: (r) => r[\"_field\"] == \"content\" or r[\"_field\"] == \"type\")" +
            "  |> filter(fn: (r) => r[\"deviceNo\"] == \"" + deviceNo + "\")" ;

        List<FluxTable> tables = queryApi.query(fluxQuery);

        List<String> contentList = new ArrayList<>();
        List<String> typeList = new ArrayList<>();
        for (FluxTable table : tables) {
            for (FluxRecord record : table.getRecords()) {

                String value = String.valueOf(record.getValue());
                String key = String.valueOf(record.getField());

                if (key.equals("content")) {
                    contentList.add(value);
                } else if (key.equals("type")) {
                    typeList.add(value);
                }
            }
        }
        for (int index=0; index < typeList.size(); index++) {
            DeviceLog deviceLog = new DeviceLog();
            deviceLog.setDeviceNo(deviceNo);
            deviceLog.setType(typeList.get(index));
            deviceLog.setContent(contentList.get(index));
            deviceLogList.add(deviceLog);
        }
        return deviceLogList;
    }
}
